package org.micode.libs.wxapp;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import org.micode.common.exception.DataException;
import org.micode.common.weixin.WeixinAuthInfo;
import org.micode.libs.wxapp.config.WxMaConfiguration;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;

@Data
@Slf4j
public abstract class WxMaHandler {

    private WeixinAuthInfo wxAuthInfo;

    private final WxMaService wxMaService;

    private WxMaJscode2SessionResult session;

    private WxMaUserService wxMaUserService;

    private final WxMaConfiguration wxMaConfiguration;

    public WxMaHandler(String appId, WxMaConfiguration wxMaConfiguration) {
        log.trace("new WxMaHandler: appId={}", appId);
        this.wxMaConfiguration = wxMaConfiguration;
        WxMaService wxMaService = getWxMaService(appId);
        if (null == wxMaService) {
            log.error("Wechat AppId is incorrect, appId=" + appId);
            throw new DataException("Wechat AppId is incorrect, appId=" + appId);
        }
        this.wxMaService = wxMaService;
    }

    public WxMaHandler(String appId, String code, String iv, String encryptedData,
                       WxMaConfiguration wxMaConfiguration) {
        this(appId, wxMaConfiguration);

        log.trace("new WxMaHandler: appId={}, code={}, iv={}, encryptedData={}",
                appId, code, iv, encryptedData);

        WeixinAuthInfo authInfo = new WeixinAuthInfo();
        authInfo.setAppId(appId);
        authInfo.setCode(code);
        authInfo.setIv(iv);
        authInfo.setEncryptedData(encryptedData);
        this.wxAuthInfo = authInfo;

        try {
            this.session = wxMaService.jsCode2SessionInfo(code);
        } catch (WxErrorException e) {
            log.error("Wechat code is incorrect, code=" + code, e);
            throw new DataException(e.getMessage());
        }

        WxMaUserService wxMaUserService = wxMaService.getUserService();
        if (null == wxMaUserService) {
            log.error("Wechat service exception, appId=" + appId);
            throw new DataException("Wechat service exception, appId=" + appId);
        }
        this.wxMaUserService = wxMaUserService;
    }

    public WxMaService getWxMaService(String appId) {
        return wxMaConfiguration.getMaService(appId);
    }

    public String getSessionKey() {
        return null == this.session ? null : this.session.getSessionKey();
    }

    public String getOpenId() {
        return null == this.session ? null : this.session.getOpenid();
    }

    public String getUnionId() {
        return null == this.session ? null : this.session.getUnionid();
    }

    public WxMaUserInfo getWxMaUserInfo() {
        if (null != wxAuthInfo && null != wxMaUserService) {
            log.trace("getWxMaUserInfo(): SessionKey={},EncryptedData={},Iv={}",
                    getSessionKey(), wxAuthInfo.getEncryptedData(), wxAuthInfo.getIv());
            return wxMaUserService.getUserInfo(getSessionKey(), wxAuthInfo.getEncryptedData(), wxAuthInfo.getIv());
        } else {
            return null;
        }
    }

    public WxMaPhoneNumberInfo getPhoneNoInfo() {
        if (null != wxAuthInfo && null != wxMaUserService) {
            log.trace("getPhoneNoInfo(): SessionKey={},EncryptedData={},Iv={}",
                    getSessionKey(), wxAuthInfo.getEncryptedData(), wxAuthInfo.getIv());
            return wxMaUserService.getPhoneNoInfo(getSessionKey(), wxAuthInfo.getEncryptedData(), wxAuthInfo.getIv());
        } else {
            return null;
        }
    }

}
